Today it is difficult to surprise anyone with the terms DoH (DNS over HTTPS), DoT (DNS over TLS) and other crypto gadgets for DNS. In case anyone has just jumped on the train and has no idea what they're talking about, DNS (Domain Name System) is a domain name system that each of us uses hundreds and thousands of times throughout the day. All human-readable names like habr.com, cia.gov and others lead to a specific IP address, which the computer can find out by contacting special servers.
Large enterprises, home Internet providers, and anyone else always has their own DNS server, because the DNS server is very simple in design. Among other considerations, they deploy their own servers for reasons of additional privacy, because the administrator of someone else’s server that we contact will see our address and will know what web resource we decided to visit.
The DNS protocol is as old as the world (~1987), so it does not provide any encryption. All DNS requests and responses travel through the network in clear text, so in the original variation, not only the DNS server administrator, but also the operators of all intermediate nodes through which traffic passes, can spy on the user. Modern solutions like DNSCrypt, DNS over HTTPS and the like solve the problem of intercepting information along the way, since they encrypt DNS requests from the user to the server and in the opposite direction. But! Protocols that encrypt traffic do not solve one important issue - the analysis of all requests on the side of the server itself, which still sees both the request itself and the IP address from which it came. The DNSCrypt project has additional lotion for this, but I was not impressed by this layering on a three-story cake. Perhaps because I have my own pie... I will be glad to receive adequate criticism, but I hope there will be no stupid comments that every person on the planet needs to have their own personal DNS server to maintain privacy.
DNS via anonymous I2P network - This is a concept in which DNS requests are encrypted, but in addition: firstly, the server administrator has no idea about the user's real IP address; secondly, the user does not know the location of the server he is accessing (also good, in order to avoid possible pressure on the administrator). DNS over I2P, or DoI2P (or even DoI) is a very interesting variation in the use of hidden networks, which we will now consider in detail.
Theory
The standard provides for the DNS server to operate on port 53 (websites, for example, run on standard ports 80 and 443), but in this case, something more interesting is what transport protocol DNS uses. This information is needed to create suitable tunnels over the I2P network.
An I2P router that provides access to the I2P network provides proxies of the SOCKS and HTTP types at the local address. In most cases, a proxy is used to work with the network, but to fine-tune the connection through a hidden network, separate tunnels are created in a special configuration file. Tunnels are either server or client. Their essence is to accept connections from the hidden network to the designated local port of a service, for example, a web server, or to transfer client connections from the local tunnel address to the hidden network. Tunnels are divided into two main types: TCP and UDP.
The main operating protocol of DNS is UDP, but the standard provides for the transfer of some information over TCP. This means that it is necessary to create two server and two client tunnels: the first for UDP connections, the second for TCP.
server
The example uses a server that is extremely easy to install and configure dnsmasq, but you can use any other one you like. The simplest configuration option for this server looks like this:
port=53
listen-address=256.257.258.259
domain-needed
bogus-priv
server=8.8.8.8
This configuration means that absolutely all requests will be sent to the address 8.8.8.8
. Such a server doesn’t make much sense, but as a layer of anonymity and just an example for an article, it’s just the thing. The server accepts requests to the IP address 256.257.258.259
, port 53
. The fictitious IP address serves only as an example, as if depicting an already existing DNS server accessible from the regular Internet. In fact, you can use a local address 127.0.0.1
and any port at your discretion if you serve users exclusively through a hidden network.
To make the DNS server accessible from I2P, server tunnels must be created. I use i2pd on Debian 10. The default tunnel configuration file is located at /etc/i2pd/tunnels.conf
. Below is the minimum configuration required to work.
[DNS-TCP]
type = server
host = 256.257.258.259
port = 53
keys = hidden-dns.dat
[DNS-UDP]
type = udpserver
host = 256.257.258.259
address = 256.257.258.259
port = 53
keys = hidden-dns.dat
Pay attention to the line address
in the UDP tunnel section. This is a necessary parameter for a non-local address, which tells i2pd from which address incoming requests from the hidden network will originate. This parameter is required for UDP tunnels. It can be omitted if the address is used 127.0.0.1
.
In the parameter keys
the keys that form the intranet address are indicated. By default they are in the directory /var/lib/i2pd
. If the file is not found, a new one is created.
Restart i2pd for the changes to take effect. The I2P address of the tunnel can be seen in the web console, in the "I2P Tunnels" tab. In my case it's dnsgzxkak4zlrrs5tfh42ob57iley4xrp7srrltn2j2yl2ynbiaq.b32.i2p
.
Client
In my case, the client machine also uses i2pd and the Debian operating system, the tunnel file is located in the same location as on the server - /etc/i2pd/tunnels.conf
. The client configuration might look like this:
[DNS-CLIENT-TCP]
type = client
address = 127.0.0.1
port = 35353
inbound.length = 2
outbound.length = 2
destination = dnsgzxkak4zlrrs5tfh42ob57iley4xrp7srrltn2j2yl2ynbiaq.b32.i2p
keepaliveinterval = 30
keys = transient-dns
[DNS-CLIENT-UDP]
type = udpclient
address = 127.0.0.1
port = 35353
destination = dnsgzxkak4zlrrs5tfh42ob57iley4xrp7srrltn2j2yl2ynbiaq.b32.i2p
keys = transient-dns
Options inbound.length
And outbound.length
are responsible for the length of incoming and outgoing tunnels. By default they are three hops, but I reduced these values to two to minimize latency a bit. Similar parameters also apply to server tunnels. Additional parameters are specified only in the first section, since the very first block defines parameters that apply to all tunnels using the same key (in my case this is transient-dns
). Keys starting with a word transient
are temporary - after each i2pd restart, the client will access the server from a new intranet address.
Parameter keepaliveinterval
on the client side is responsible for sending one service packet to the server’s I2P router. It is the I2P router, and not the DNS server or any other application that listens to the I2P server tunnel. The value is specified in seconds. This option allows the client to have an up-to-date LeaseSet (server contact information), which changes every 10 minutes. If there is no LeaseSet at the time of the actual DNS request, there will be a noticeable delay (~2-5 seconds), at which time the LeaseSet will be searched. Option keepaliveinterval
appeared in i2pd 2.40. Article updated in March 2022.
For new tunnels to be created, you need to restart i2pd. At this point it may seem like the job is done. But no, there is one more nuance left.
The file responsible for configuring DNS on my operating system (Debian 10) does not support specifying a port. You can only specify the server IP address. All requests will be sent to the port 53
, but our tunnel hangs on the port 35353
. If you specify the port in client tunnels 53
, an error will occur and tunnels will not be created, because all ports below 1024 are privileged - reserved for special needs. Only a superuser (root) can start a service on such a port, and i2pd, like other application programs, works without superuser rights. Before running i2pd (or any other third party software) as root, take a deep breath, and then read on..
Remove from /etc/resolv.conf
the old DNS, so that all requests go exclusively through I2P, and add a single server - local: nameserver 127.0.0.1
. This will tell the operating system to resolve names to addresses by contacting 127.0.0.1:53
. All that remains is to ask the system kernel to redirect requests from the port 53
on 35353
, where our TCP/UDP tunnels hang, and then send responses in the opposite direction. It's time for the magic of iptables (sorry I'm not a newfangled netfilter, I'm an old school magician).
iptables -t nat -A PREROUTING -i lo -p udp --dport 53 -j REDIRECT --to-port 35353
iptables -t nat -I OUTPUT -p udp -d 127.0.0.1 --dport 53 -j REDIRECT --to-port 35353
iptables -t nat -A PREROUTING -i lo -p tcp --dport 53 -j REDIRECT --to-port 35353
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 53 -j REDIRECT --to-port 35353
Do you hear? Listen, it's fanfare! Check the resolution in any convenient way, I will use the utility nslookup
:
acetone@adeb:~$ nslookup habr.com
Server: 127.0.0.1
Address: 127.0.0.1#53
Non-authoritative answer:
Name: habr.com
Address: 178.248.237.68
Afterword
During setup, I noticed that dnsmasq in standby mode occupied only a UDP socket, but I decided to leave the TCP tunnel in accordance with the DNS standard, which provides for the transfer of some information via TCP. Be that as it may, the functionality described is perfectly observed even in the absence of TCP tunnels.
The above configuration takes an average of 1-2 seconds per request and response to the DNS server. If your results seem too slow, you can reduce the length of the server and client tunnels to 2. Options with tunnels to a single transit node are possible, but this only applies to devices that you are not worried about being compromised: for example, if your DNS is not secret , the length of the tunnels can be equal to one or even zero! In this case, you give the user the opportunity to build a longer anonymizing tunnel on his side. The main thing is to do everything wisely and not be lazy to get acquainted with documentation, and consult with knowledgeable people.
As a demonstration (and maybe for permanent use), you can use the DNS server, the user configs for which are given above.